package com.taomus.mytools.asmuitls;
import java.io.PrintStream;
import java.io.PrintWriter;

import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.GeneratorAdapter;
import org.objectweb.asm.commons.Method;
import org.objectweb.asm.util.TraceClassVisitor;

public class AsmUtils_old extends ClassLoader{
	private ClassWriter cw1 = null;
	private TraceClassVisitor cw=null;
	private GeneratorAdapter ga = null;
	private String name;
	public AsmUtils_old() {
		cw1 = new ClassWriter(ClassWriter.COMPUTE_MAXS);
		cw = new TraceClassVisitor(cw1, new PrintWriter(System.out));
	}
	
	public AsmUtils_old(String name) {
		this();
		this.createConstructor(name);
	}
	
	public void createFied(String scope,String name,Object value){
		int defaultScope = Opcodes.ACC_PUBLIC;
		if (scope.indexOf(" ") != -1) {
			String[] scopes = scope.split(" ");
			for (String s : scopes) {
				defaultScope += getScope(s);
			}
		}
		String type = "L"+Type.getType(value.getClass().getSimpleName()).getDescriptor();
		cw.visitField(defaultScope, name,type,null,value).visitEnd();
	}

	public void setField(String name,Object value){
		ga.loadThis();
		ga.visitLdcInsn(value);
		ga.putField(Type.getType(this.name), name,Type.getType(value.getClass().getSimpleName()));
	}
	
	public void getField(String name,String type){
		ga.loadThis();
		ga.getField(Type.getType(this.name), name, Type.getType(type));
		ga.getStatic(Type.getType(System.class),"out", Type.getType(PrintStream.class));
		ga.invokeVirtual(Type.getType(PrintStream.class),Method.getMethod("void print(Integer)"));
	}
	
	public void getField(String name,Class<?> cl){
		ga.loadThis();
		ga.getField(Type.getType(this.name), name,Type.getType(cl));
	}
	
	public void createConstructor(String name) {
		this.name = name;
		cw.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC, name, null, "java/lang/Object", null);
		Method m = Method.getMethod("void <init>()");
		GeneratorAdapter ga = new GeneratorAdapter(Opcodes.ACC_PUBLIC, m, null, null, cw);
		ga.loadThis();
		ga.invokeConstructor(Type.getType(Object.class), m);
		ga.returnValue();
		ga.endMethod();
	}
	public void createMethod(String scope, String m) {
		Method method = Method.getMethod(m);
		int defaultScope = Opcodes.ACC_PUBLIC;
		if (scope.indexOf(" ") != -1) {
			String[] scopes = scope.split(" ");
			for (String s : scopes) {
				defaultScope += getScope(s);
			}
		}
		ga = new GeneratorAdapter(defaultScope, method, null, null, cw);
	}
	public void addStatic(Type owner,String name,Type type){
		ga.getStatic(owner, name, type);
	}
	public void addInvoke(Type owner,String m){
		ga.invokeVirtual(owner,Method.getMethod(m));
	}
	public void addInvokeInterface(Type owner,String m){
		ga.invokeInterface(owner,Method.getMethod(m));
	}
	public void returnValue(){
		ga.returnValue();
	}
	public void end(){
		ga.endMethod();
		cw.visitEnd();
	}
	
	public void addInvokeDynamic(){
		//ga.invokeDynamic(name, desc, bsm, bsmArgs);
	}
	
	public void addValue(Object value){
		if(value instanceof Boolean || value.equals(boolean.class)){
			ga.push((Boolean)value);
		}else if(value instanceof Integer || value.equals(int.class)){
			ga.push((Integer)value);
		}else if(value instanceof Double || value.equals(double.class)){
			ga.push((Double)value);
		}else if(value instanceof Float || value.equals(float.class)){
			ga.push((Float)value);
		}else if(value instanceof Long || value.equals(long.class)){
			ga.push((Long)value);
		}else if(value instanceof String){
			ga.push((String)value);
		}else if(value instanceof Handle){
			ga.push((Handle)value);
		}else if(value instanceof Type){
			ga.push((Type)value);
		}
	}
	
	public void addCode(){
		
	}
	
	public void print(Object obj){
		ga.getStatic(Type.getType(System.class),"out", Type.getType(PrintStream.class));
		ga.push(String.valueOf(obj));
		ga.invokeVirtual(Type.getType(PrintStream.class),Method.getMethod("void print(String)"));
	}
	
	public void println(Object obj){
		ga.getStatic(Type.getType(System.class),"out", Type.getType(PrintStream.class));
		ga.push(String.valueOf(obj));
		ga.invokeVirtual(Type.getType(PrintStream.class),Method.getMethod("void println(String)"));
	}
	
	private int getScope(String scope) {
		switch (scope) {
		case "private":
			return Opcodes.ACC_PRIVATE;
		case "protected":
			return Opcodes.ACC_PROTECTED;
		case "static":
			return Opcodes.ACC_STATIC;
		case "final":
			return Opcodes.ACC_FINAL;
		case "abstract":
			return Opcodes.ACC_ABSTRACT;
		case "enum":
			return Opcodes.ACC_ENUM;
		case "volatile":
			return Opcodes.ACC_VOLATILE;
		case "annotation":
			return Opcodes.ACC_ANNOTATION;
		case "bridge":
			return Opcodes.ACC_BRIDGE;
		case "deprecated":
			return Opcodes.ACC_DEPRECATED;
		case "interface":
			return Opcodes.ACC_INTERFACE;
		case "native":
			return Opcodes.ACC_NATIVE;
		case "super":
			return Opcodes.ACC_SUPER;
		case "synchronized":
			return Opcodes.ACC_SYNCHRONIZED;
		case "synthetic":
			return Opcodes.ACC_SYNTHETIC;
		case "transient":
			return Opcodes.ACC_TRANSIENT;
		case "varargs":
			return Opcodes.ACC_VARARGS;
		case "public":
		default:
			return Opcodes.ACC_PUBLIC;
		}
	}

	public Class<?> loadClass2(String name){
		byte[] bytes = cw1.toByteArray();
		System.out.println(bytes.length);
		Class<?> cl = this.defineClass(name,bytes,0,bytes.length);
		return cl;
	}
}